/*****************************************************************************
 *   Copyright 2005 Tim A Wang
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 ****************************************************************************/
package com.jb.web.bean;

import com.jb.faces.el.AttributeEvaluator;
import com.jb.framework.PersistentContext;
import com.jb.framework.util.PropUtil;
import com.jb.web.bean.inspector.OptionPropertyEditor;
import com.jb.web.bean.inspector.PropertyInfo;
import com.jb.web.context.WebContext;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import com.jb.faces.context.FacesContext;

import com.jb.framework.util.BeanUtil;

import com.jb.util.ClassUtil;

import javax.servlet.jsp.el.ELException;


public class Form extends Table {
    static final long serialVersionUID = 123123L;

    static {
        publish(Form.class, GENERAL, "method", new OptionPropertyEditor("static:post,Post;get,Get;"));

        publish(Form.class, GENERAL, "encType");
        publish(Form.class, GENERAL, "action");
        publish(Form.class, GENERAL, "actionForwards");
        publish(Form.class, EVENT_HANDLER, "onSubmit");
    }

    private String action;
    private String actionForwards;
    private String encType;
    private String method;

    public void setAction(String pAction) {
        this.action = pAction;
    }

    public String getAction() {
        return action;
    }

    public void setActionForwards(String actionForwards) {
        this.actionForwards = actionForwards;
    }

    public String getActionForwards() {
        return actionForwards;
    }

    public void setDefault(PersistentContext pCtx) {
        setStyleClass("jbForm");
        this.setColumns(2);
        setGridLineWidth(2);
        setRows(4);
        this.setWidth("300px");
        valueChanged(pCtx);

        setAction("${ctx.pageName}.xsp}");

        TableRow row = getRow(0);
        row.setCols(1);
        row.getCellAt(0).setColSpan(2);
        row.getCellAt(0).setStyleClass("jb_window_title");
        row.getCellAt(0).setValue("Form Title");
        row.valueChanged(pCtx);

        row = getRow(1);

        TableCell cell = row.getCellAt(0);
        cell.setStyleClass("propertyFieldLabel");
        cell.setValue("Label 1");
        cell = row.getCellAt(1);
        cell.setStyleClass("propertyFieldCell");

        FormField field = (FormField) ClassUtil.createInstance(TextField.class);
        field.setStyleClass("jbFormField");
        field.setId(getId() + "field1");
        cell.addChild(field);

        row = getRow(2);
        cell = row.getCellAt(0);
        cell.setStyleClass("propertyFieldLabel");
        cell.setValue("Label 2");
        cell = row.getCellAt(1);
        cell.setStyleClass("propertyFieldCell");
        field = (FormField) ClassUtil.createInstance(TextField.class);
        field.setStyleClass("jbFormField");
        field.setId(getId() + "field3");
        cell.addChild(field);

        row = getRow(3);
        row.setSequence(100);
        row.setCols(1);
        cell = row.getCellAt(0);
        cell.setStyleClass("alignMiddle");
        cell.setColSpan(2);

        Button btn = (Button) ClassUtil.createInstance(com.jb.web.bean.Button.class);
        btn.setId(getId() + "sub");
        btn.setFormAction("submit");
        btn.setLabel("${resource.submit}");
        cell.addChild(btn);

        row.valueChanged(pCtx);
        setAction("${context.pageName}.xsp");
    }

    public void setEncType(String pEncType) {
        this.encType = pEncType;
    }

    public String getEncType() {
        return encType;
    }

    public List getFields() {
        return getDescendants(FormField.class);
    }

    public FormField getFormField(String fieldName) {
        List fields = getFields();
        for (int i = 0; i < fields.size(); i++) {
            FormField f = (FormField) fields.get(i);
            if (fieldName.equals(f.getFieldName())) {
                return f;
            }
        }

        return null;
    }

    public List getMetaData(String pClassName) {
        try {
            List list = new ArrayList();
            Class clazz = ClassUtil.getClass(pClassName);
            Method[] methods = clazz.getMethods();

            for (int i = 0; i < methods.length; i++) {
                if (!Modifier.isPublic(methods[i].getModifiers())) {
                    continue;
                }

                if (methods[i].getName().startsWith("get") || methods[i].getName().startsWith("is")) {
                    list.add(new PropertyInfo(methods[i].getName(), methods[i].getReturnType()));
                }
            }

            return list;
        } catch (Exception e) {
            e.printStackTrace();

            return Collections.EMPTY_LIST;
        }
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public String getMethod() {
        return method;
    }

    public void setOnSubmit(String submitAction) {
        this.setOnUpdateModel(submitAction);
    }

    public String getOnSubmit() {
        return getOnUpdateModel();
    }

    //
    //This method assigns a bean to the form
    //it matches client id of a field with 
    //bean property
    //
    public void populate(WebContext pCtx, Object bean) {
        //get instance 
        if (bean == null) {
            return;
        }

        //populate value from model
        HashMap hm = PropUtil.getPropertyValues(bean.getClass(), bean);

        for (Iterator fields = getFields().iterator(); fields.hasNext();) {
            FormField field = (FormField) fields.next();

            //do not set value for button
            if (field instanceof RadioButton) {
                continue;
            }

            Object fieldValue = hm.get(field.getFieldName());

            if (fieldValue != null) {
                field.setModelBean(fieldValue);

                field.setValue(fieldValue.toString());
            } else {
                field.setModelBean(null);

                field.setValue("");
            }
        }
    }

    public void processDecodes(FacesContext pCtx) {
        if (isMyEvent((WebContext) pCtx)) {
            super.processDecodes(pCtx);
        }
    }

    /**
     * Only validate if the request is made for this form
     *
     * @param pCtx
     */
    public void processValidators(FacesContext pCtx) {
        if (isMyEvent((WebContext) pCtx)) {
            super.processValidators(pCtx);
        }
    }

    public void resetForm() {
        List fields = getFields();

        for (int i = 0; i < fields.size(); i++) {
            FormField f = (FormField) fields.get(i);
            f.setDecodedValue(null);
            f.setModelBean(null);
            f.setValue(null);
        }

        //  synch();
    }

    public boolean showDefaultButton() {
        return false;
    }

    public String toString() {
        return "Form " + getId();
    }

    public void updateView(WebContext pCtx) {
        super.updateView(pCtx);

        if (isMyEvent(pCtx)) {
            //only forward if there is no request for render response, usually related to an error
            if (!pCtx.isRenderResponse) { 
                String actionForwards = getActionForwards();
                if ((actionForwards != null) && (actionForwards.length() > 0)) {
                    try {
                        actionForwards = (String)AttributeEvaluator.evaluate(pCtx, this, actionForwards, String.class);
                        pCtx.setRedirectPage(actionForwards);
                    } catch (ELException e) {
                        pCtx.addErrorMessage(this, "Expression Error " + e.getMessage());
                    }
                }
            }
        }
    }
}
